/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "geofence_rdb.h"
#include <string>
#include <cerrno>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <linux/netlink.h>
#include <unistd.h>
#include "dummy_values_bucket.h"
#include "geofence_common.h"

using namespace OHOS::NativeRdb;
namespace OHOS {
namespace Msdp {
namespace {
const std::string DATABASE_NAME = "/data/MsdpStub.db";
const std::string CREATE_TABLE = std::string("CREATE TABLE IF NOT EXISTS GEOFENCETRACK") +
    std::string("(ID INTEGER PRIMARY KEY AUTOINCREMENT, TIME STRING, SCREENSTATE STRING, CELL STRING)");
const int32_t TIMER_INTERVAL = 3;
const int32_t ERR_INVALID_FD = -1;
const int32_t SCREEN_AWAKE = 0;
const int32_t SCREEN_INACTIVE = 1;

std::unique_ptr<GeofenceRdb> msdpRdb_ = std::make_unique<GeofenceRdb>();
}

bool GeofenceRdb::Init()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GeofenceRdbInit: enter");
    InitRdbStore();

    InitTimer();
    StartThread();

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GeofenceRdbInit: exit");
    return true;
}

void GeofenceRdb::InitRdbStore()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    int errCode = ERR_OK;
    RdbStoreConfig config(DATABASE_NAME);
    InsertOpenCallback helper;
    store_ = RdbHelper::GetRdbStore(config, 1, helper, errCode);

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
}

ErrCode GeofenceRdb::RegisterLocation(CallbackLocationImpl callback)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    callbacksLocationImpl_ = callback;
    return ERR_OK;
}

ErrCode GeofenceRdb::UnregisterLocation() const
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    return ERR_OK;
}

ErrCode GeofenceRdb::RegisterCloud(const GeofenceDataUtils::PoiOptions& poiOptions,\
    CallbackCloudImpl callback)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    callbacksCloudImpl_ = callback;
    poiOptions_ = poiOptions;
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "poiOptions_.keyword = %{public}s", poiOptions_.keyword.c_str());
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "poiOptions_.poiType = %{public}s", poiOptions_.poiType.c_str());
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "poiOptions_.poiCity = %{public}s", poiOptions_.poiCity.c_str());
    return ERR_OK;
}

ErrCode GeofenceRdb::UnregisterCloud() const
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    return ERR_OK;
}

ErrCode GeofenceRdb::Enable()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "Exit");
    return ERR_OK;
}

ErrCode GeofenceRdb::Disable()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "Exit");
    return ERR_OK;
}


ErrCode GeofenceRdb::NotifyMsdpLocationImpl(GeofenceDataUtils::LocationData& locationData)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    callbacksLocationImpl_(locationData);

    return ERR_OK;
}

ErrCode GeofenceRdb::NotifyMsdpCloudImpl(GeofenceDataUtils::CloudData& fenceData)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    callbacksCloudImpl_(fenceData);

    return ERR_OK;
}

std::vector<double> GeofenceRdb::JudgeRdbLocationData(int timeStamp, std::vector<double> location)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    for (auto iter = rdbDataMap_.begin(); iter != rdbDataMap_.end(); ++iter) {
        if (iter->first == timeStamp) {
            notifyLocationFlag_ = false;
            GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "Location data is not changed");
            return location;
        }
    }
    rdbDataMap_.insert(std::make_pair(timeStamp, location));
    notifyLocationFlag_ = true;

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "timeStamp = %{public}d, location x = %{public}lf,\
        location y = %{public}lf", timeStamp, location[0], location[1]);

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");

    return location;
}

int GeofenceRdb::TrigerLocationDatabaseObserver()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    int columnIndex;
    int intVal;
    double coordinate;
    GeofenceDataUtils::LocationData locationData;
    int timeStamp;
    std::string cell;
    std::string str;

    if (store_ == nullptr) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "store_ is not exist");
        sleep(30);
        InitRdbStore();
        return -1;
    }

    std::unique_ptr<ResultSet> resultSet =
        store_->QuerySql("SELECT * FROM GEOFENCELOCATION WHERE ID = (SELECT max(ID) from GEOFENCELOCATION)");

    if (resultSet == nullptr) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "database is not exist");
        return -1;
    }

    int ret = resultSet->GoToFirstRow();
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GoToFirstRow = %{public}d", ret);
    if (ret != ERR_OK) {
        sleep(30);
        return -1;
    }

    ret = resultSet->GetColumnIndex("ID", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }
    ret = resultSet->GetInt(columnIndex, intVal);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "id = %{public}d", intVal);
    if (ret != ERR_OK) {
        return -1;
    }

    ret = resultSet->GetColumnIndex("TIME_STAMP", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GEOFENCE_TIMESTAMP GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckGeofenceStamp: GetColumnIndex failed");
        return -1;
    }
    ret = resultSet->GetInt(columnIndex, timeStamp);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GeofenceLocation timeStamp = %{public}d", timeStamp);
    if (ret != ERR_OK) {
        return -1;
    }

    ret = resultSet->GetColumnIndex("X", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }

    ret = resultSet->GetDouble(columnIndex, coordinate);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate X = %{public}lf",coordinate);
    if (ret != ERR_OK) {
        return -1;
    }
    locationData.location.push_back(coordinate);

    ret = resultSet->GetColumnIndex("Y", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }

    ret = resultSet->GetDouble(columnIndex, coordinate);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate Y = %{public}lf", coordinate);
    if (ret != ERR_OK) {
        return -1;
    }
    locationData.location.push_back(coordinate);

    ret = resultSet->GetColumnIndex("CELL", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "CELL GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckGeofenceStamp: GetColumnIndex failed");
        return -1;
    }
    ret = resultSet->GetString(columnIndex, cell);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GeofenceLocation CELL = %{public}s", cell.c_str());
    if (ret != ERR_OK) {
        return -1;
    }
    locationData.cell = cell;

    ret = resultSet->Close();
    if (ret != ERR_OK) {
        return -1;
    }

    JudgeRdbLocationData(timeStamp, locationData.location);
    if (notifyLocationFlag_) {
        NotifyMsdpLocationImpl(locationData);
        notifyLocationFlag_ = false;
    }

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
    return columnIndex;
}

int GeofenceRdb::TrigerCloudDatabaseObserver()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    int columnIndex;
    int intVal;
    int poiNum;
    double coordinate;
    double radius;
    GeofenceDataUtils::CloudData cloudData;
    double centerX;
    double centerY;
    int cacheFlag;
    std::string str;

    if (std::size(poiOptions_.keyword) == 0) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "poiOptions is null, poiOptions not subscribed");
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
        return -1;
    } else {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "poiOptions_.keyword = %{public}s", poiOptions_.keyword.c_str());
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "poiOptions_.poiType = %{public}s", poiOptions_.poiType.c_str());
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "poiOptions_.poiCity = %{public}s", poiOptions_.poiCity.c_str());
    }

    if (store_ == nullptr) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "store_ is not exist");
        sleep(30);
        InitRdbStore();
        return -1;
    }
    str = "SELECT * FROM GEOFENCECLOUD WHERE ID = (SELECT max(ID) from GEOFENCECLOUD) AND KEYWORD ='" +
        poiOptions_.keyword + "' AND POITYPE = '" + poiOptions_.poiType + "' AND POICITY = '" +
        poiOptions_.poiCity + "'";
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "str = %{public}s", str.c_str());
    std::unique_ptr<ResultSet> resultSet = store_->QuerySql(str);

    if (resultSet == nullptr) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "database is not exist");
        return -1;
    }

    int ret = resultSet->GoToFirstRow();
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GoToFirstRow = %{public}d", ret);
    if (ret != ERR_OK) {
        sleep(30);
        return -1;
    }

    ret = resultSet->GetColumnIndex("ID", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }
    ret = resultSet->GetInt(columnIndex, intVal);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "id = %{public}d", intVal);
    if (ret != ERR_OK) {
        return -1;
    }

    ret = resultSet->GetColumnIndex("POINUM", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }
    ret = resultSet->GetInt(columnIndex, poiNum);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "fence = %{public}d", poiNum);
    if (ret != ERR_OK) {
        return -1;
    }

    for (int coordinateType = 0; coordinateType < poiNum; coordinateType++) {
        cloudData.fence.push_back(std::vector<double>());
        ret = resultSet->GetColumnIndex("X" + std::to_string(coordinateType), columnIndex);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
        if (ret != ERR_OK) {
            GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
            return -1;
        }

        ret = resultSet->GetDouble(columnIndex, coordinate);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate X%{public}d = %{public}lf", coordinateType ,coordinate);
        if (ret != ERR_OK) {
            return -1;
        }
        cloudData.fence[coordinateType].push_back(coordinate);

        cloudData.fence.push_back(std::vector<double>());
        ret = resultSet->GetColumnIndex("Y" + std::to_string(coordinateType), columnIndex);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
        if (ret != ERR_OK) {
            GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
            return -1;
        }

        ret = resultSet->GetDouble(columnIndex, coordinate);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate Y%{public}d = %{public}lf", coordinateType ,coordinate);
        if (ret != ERR_OK) {
            return -1;
        }
        cloudData.fence[coordinateType].push_back(coordinate);
    }

    ret = resultSet->GetColumnIndex("CENTERX", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }

    ret = resultSet->GetDouble(columnIndex, centerX);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "centerX = %{public}lf",centerX);
    if (ret != ERR_OK) {
        return -1;
    }
    cloudData.center.push_back(centerX);

    ret = resultSet->GetColumnIndex("CENTERY", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }

    ret = resultSet->GetDouble(columnIndex, centerY);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "centerY = %{public}lf", centerY);
    if (ret != ERR_OK) {
        return -1;
    }
    cloudData.center.push_back(centerY);

    ret = resultSet->GetColumnIndex("RADIUS", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }
    ret = resultSet->GetDouble(columnIndex, radius);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "radius = %{public}lf", radius);
    if (ret != ERR_OK) {
        return -1;
    }
    cloudData.radius = radius;

    ret = resultSet->GetColumnIndex("CACHEFLAG", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return -1;
    }
    ret = resultSet->GetInt(columnIndex, cacheFlag);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "cacheFlag = %{public}d", cacheFlag);
    if (ret != ERR_OK) {
        return -1;
    }

    if (cacheFlag == 0) {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "change cacheflag = 1");
        ValuesBucket values;
        values.PutInt("CACHEFLAG", 1);
        str = "UPDATE GEOFENCECLOUD SET CACHEFLAG = '1' WHERE ID = '" + std::to_string(intVal) + "'";
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "str = %{public}s", str.c_str());
        int32_t resultUpdate =store_->Update(columnIndex, "GEOFENCECLOUD", values);

        if (resultUpdate == -1) {
            GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "change cacheflag = 1 failed");
        } else {
            GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "change cacheflag = 1 success");
        }
    }

    ret = resultSet->Close();
    if (ret != ERR_OK) {
        return -1;
    }

    memset(&poiOptions_, 0, sizeof(poiOptions_));
    NotifyMsdpCloudImpl(cloudData);
    return columnIndex;
}

GeofenceDataUtils::CloudData GeofenceRdb::GetCloudCacheData(const GeofenceDataUtils::PoiOptions& poiOptions)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    int columnIndex;
    int intVal;
    int poiNum;
    double coordinate;
    GeofenceDataUtils::CloudData cloudData;
    GeofenceDataUtils::CloudData resultData;
    double centerX;
    double centerY;
    double radius;

    if (store_ == nullptr) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "store_ is not exist");
        InitRdbStore();
        return resultData;
    }

    std::unique_ptr<ResultSet> resultSet =
        store_->QuerySql("SELECT * FROM GEOFENCECLOUD WHERE ID = (SELECT max(ID) from GEOFENCECLOUD) AND KEYWORD ='" + poiOptions.keyword + "' AND POITYPE = '" + poiOptions.poiType + "' AND POICITY = '" + poiOptions.poiCity + "' AND CACHEFLAG = '1'");

    if (resultSet == nullptr) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "database is not exist");
        return resultData;
    }

    int ret = resultSet->GoToFirstRow();
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GoToFirstRow = %{public}d", ret);
    if (ret != ERR_OK) {
        return resultData;
    }

    ret = resultSet->GetColumnIndex("ID", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return resultData;
    }
    ret = resultSet->GetInt(columnIndex, intVal);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "id = %{public}d", intVal);
    if (ret != ERR_OK) {
        return resultData;
    }

    ret = resultSet->GetColumnIndex("FENCE", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return resultData;
    }
    ret = resultSet->GetInt(columnIndex, poiNum);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "fence = %{public}d", poiNum);
    if (ret != ERR_OK) {
        return resultData;
    }

    for (int coordinateType = 0; coordinateType < poiNum; coordinateType++) {
        cloudData.fence.push_back(std::vector<double>());
        ret = resultSet->GetColumnIndex("X" + std::to_string(coordinateType), columnIndex);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
        if (ret != ERR_OK) {
            GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
            return resultData;
        }

        ret = resultSet->GetDouble(columnIndex, coordinate);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate X%{public}d = %{public}lf", coordinateType ,coordinate);
        if (ret != ERR_OK) {
            return resultData;
        }
        cloudData.fence[coordinateType].push_back(coordinate);

        cloudData.fence.push_back(std::vector<double>());
        ret = resultSet->GetColumnIndex("Y" + std::to_string(coordinateType), columnIndex);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
        if (ret != ERR_OK) {
            GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
            return resultData;
        }

        ret = resultSet->GetDouble(columnIndex, coordinate);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate Y%{public}d = %{public}lf", coordinateType ,coordinate);
        if (ret != ERR_OK) {
            return resultData;
        }
        cloudData.fence[coordinateType].push_back(coordinate);
    }

    ret = resultSet->GetColumnIndex("CENTERX", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return resultData;
    }

    ret = resultSet->GetDouble(columnIndex, centerX);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate X = %{public}lf",coordinate);
    if (ret != ERR_OK) {
        return resultData;
    }
    cloudData.center.push_back(centerX);

    ret = resultSet->GetColumnIndex("CENTERY", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return resultData;
    }

    ret = resultSet->GetDouble(columnIndex, centerY);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "coordinate Y = %{public}lf", coordinate);
    if (ret != ERR_OK) {
        return resultData;
    }
    cloudData.center.push_back(centerY);

    ret = resultSet->GetColumnIndex("RADIUS", columnIndex);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TrigerDatabaseObserver GetColumnIndex = %{public}d", columnIndex);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "CheckID: GetColumnIndex failed");
        return resultData;
    }
    ret = resultSet->GetDouble(columnIndex, radius);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "radius = %{public}lf", radius);
    if (ret != ERR_OK) {
        return resultData;
    }
    cloudData.radius = radius;

    ret = resultSet->Close();
    if (ret != ERR_OK) {
        return resultData;
    }

    return cloudData;
}

int32_t GeofenceRdb::SetTrack(std::string timeString, int32_t screenState, std::string cell)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    int ret = -1;
    int64_t ID;

    if (store_ == nullptr) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "store_ is not exist");
        InitRdbStore();
        return -1;
    }

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "start to create table");
    ret = store_->ExecuteSql(CREATE_TABLE);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "failed to create table");
        return ret;
    }

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "TIME = %{public}s", timeString.c_str());
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "screenState = %{public}d", screenState);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "cell = %{public}s", cell.c_str());

    ValuesBucket values;
    values.PutString("TIME", timeString);
    if (screenState == SCREEN_AWAKE) {
        values.PutString("SCREENSTATE", std::string("AWAKE"));
    } else if (screenState == SCREEN_INACTIVE) {
        values.PutString("SCREENSTATE", std::string("INACTIVE"));
    } else {
        values.PutString("SCREENSTATE", std::string("SLEEP"));
    }
    values.PutString("CELL", cell);

    ret = store_->Insert(ID, "GEOFENCETRACK", values);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "ret = %{public}d", ret);
    if (ret != ERR_OK) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "failed to insert data");
        return ret;
    }
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "RdbdataInsert: insert success");
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
    return ERR_OK;
}

void GeofenceRdb::InitTimer()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    epFd_ = epoll_create1(EPOLL_CLOEXEC);
    if (epFd_ == -1) {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "create epoll fd fail.");
    }
    timerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
    if (timerFd_ == ERR_INVALID_FD) {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "create timer fd fail.");
    }
    SetTimerInterval(TIMER_INTERVAL);
    fcntl(timerFd_, F_SETFL, O_NONBLOCK);
    callbacks_.insert(std::make_pair(timerFd_, &GeofenceRdb::TimerCallback));
    if (RegisterTimerCallback(timerFd_, EVENT_TIMER_FD)) {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "register timer fd fail.");
    }
}

void GeofenceRdb::SetTimerInterval(int interval)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    struct itimerspec itval;

    if (timerFd_ == ERR_INVALID_FD) {
        return;
    }

    timerInterval_ = interval;

    if (interval < 0) {
        interval = 0;
    }

    itval.it_interval.tv_sec = interval;
    itval.it_interval.tv_nsec = 0;
    itval.it_value.tv_sec = interval;
    itval.it_value.tv_nsec = 0;

    if (timerfd_settime(timerFd_, 0, &itval, nullptr) == -1) {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "set timer failed");
    }

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    return;
}

void GeofenceRdb::TimerCallback()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    unsigned long long timers;
    if (read(timerFd_, &timers, sizeof(timers)) == -1) {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "read timer fd fail.");
        return;
    }
    TrigerLocationDatabaseObserver();
    TrigerCloudDatabaseObserver();
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
}

int GeofenceRdb::RegisterTimerCallback(const int fd, const EventType et)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    struct epoll_event ev;

    ev.events = EPOLLIN;
    if (et == EVENT_TIMER_FD) {
        ev.events |= EPOLLWAKEUP;
    }

    ev.data.ptr = reinterpret_cast<void*>(this);
    ev.data.fd = fd;
    if (epoll_ctl(epFd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
        GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "epoll_ctl failed, error num =%{public}d", errno);
        return -1;
    }

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
    return 0;
}

void GeofenceRdb::StartThread()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    std::make_unique<std::thread>(&GeofenceRdb::LoopingThreadEntry, this)->detach();
}

void GeofenceRdb::LoopingThreadEntry()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    int nevents = 0;
    size_t cbct = callbacks_.size();
    struct epoll_event events[cbct];

    while (true) {
        int timeout = 0;

        nevents = epoll_wait(epFd_, events, cbct, timeout);
        if (nevents == -1) {
            continue;
        }
        for (int n = 0; n < nevents; ++n) {
            if (events[n].data.ptr) {
                GeofenceRdb *func = const_cast<GeofenceRdb *>(this);
                (callbacks_.find(events[n].data.fd)->second)(func);
            }
        }
    }
}

ErrCode IgeofenceImplInterface::Enable()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    if (msdpRdb_ == nullptr) {
        msdpRdb_ = std::make_unique<GeofenceRdb>();
    }

    msdpRdb_->Init();

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "Exit");
    return ERR_OK;
}

ErrCode IgeofenceImplInterface::Disable()
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    msdpRdb_->Disable();

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "Exit");
    return ERR_OK;
}

ErrCode IgeofenceImplInterface::RegisterLocationCallback(CallbackLocationImpl callback)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    msdpRdb_->RegisterLocation(callback);

    return ERR_OK;
}

ErrCode IgeofenceImplInterface::UnregisterLocationCallback() const
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    msdpRdb_->UnregisterLocation();

    return ERR_OK;
}

ErrCode IgeofenceImplInterface::RegisterCloudCallback(const GeofenceDataUtils::PoiOptions& poiOptions,\
    CallbackCloudImpl callback)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");

    msdpRdb_->RegisterCloud(poiOptions, callback);

    return ERR_OK;
}

ErrCode IgeofenceImplInterface::UnregisterCloudCallback() const
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    msdpRdb_->UnregisterCloud();

    return ERR_OK;
}

GeofenceDataUtils::CloudData IgeofenceImplInterface::GetCloudCacheDataImpl(
    const GeofenceDataUtils::PoiOptions& poiOptions)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    GeofenceDataUtils::CloudData cloudData;
    cloudData = msdpRdb_->GetCloudCacheData(poiOptions);
    if (std::size(cloudData.fence) == 0) {
        GEOFENCE_HILOGE(GEOFENCE_MODULE_SERVICE, "GetCloudCacheData fail.");
        return cloudData;
    }
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
    return cloudData;
}

void IgeofenceImplInterface::SetTrackImpl(std::string timeString, int32_t screenState, std::string cell)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");
    msdpRdb_->SetTrack(timeString, screenState, cell);
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "exit");
    return;
}

int InsertOpenCallback::OnCreate(RdbStore &store)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "Exit");
    return ERR_OK;
}

int InsertOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "enter");

    GEOFENCE_HILOGI(GEOFENCE_MODULE_SERVICE, "Exit");
    return ERR_OK;
}
}
}

